#include<stdio.h>
#include<string.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netinet/ip.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>

#define SERV_IP "0"
#define SERV_PORT 6666

void *do_client(void *arg);     //线程函数的声明
int server_init(char *ip,int port,int backlog)
{
    //socket
    int listend;    //用于保存 监听 套结字
    listend=socket(PF_INET,SOCK_STREAM,0);
    if(listend==-1)
    {
        perror("socket");
        return -1;
    }
    printf("socket success!\n");
    //填充协议 ip 端口
    struct sockaddr_in saddr={
        .sin_family         = PF_INET, //ipv4协议  
        .sin_port           = htons(port), //端口
        .sin_addr.s_addr    = inet_addr(ip) //本地还回ip
    };
    //地址重用
    int opt=1;
    //设置地址重用
    setsockopt(listend,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
    int ret = bind(listend,(struct sockaddr*) &saddr,sizeof(saddr));
    if(ret==-1){
        perror("bind");
        exit(-1);
    }
    printf("bind success!\n");

    ret = listen(listend,backlog);
    if(ret==-1)
    {
        perror("listen");
        exit(-1);
    }
    printf("listen.....等待 客户端连接！\n");
    return listend;
}


void loading(int connfd)
{
    char out[1024]={0};
    int i;
    for(i=0;i<=100;i++)
    {
        sprintf(out,"(%d%%)\r",i);
        write(connfd,out,sizeof(out));
        usleep(100000);
    }
    strcpy(out,"\nloading success!\n");
    write(connfd,out,sizeof(out));
}

int t[11]={0};
int *arr=t;
int length=0;

int main()
{
    //server_init
    int listend;
    int connfd; //通信套结字
    int ret;
    struct sockaddr_in client_addr={0};
    socklen_t clen = sizeof(client_addr);
    listend=server_init(SERV_IP,SERV_PORT,10);
    if(listend==-1)
    {
        perror("server_init");
        exit(-1);
    }
    printf("wait for clien\n");
    //accept //调用accept后，listend监听套结字变为connfd通信套结字
    while(1)
    {
       connfd= accept(listend,(struct sockaddr*)&client_addr,&clen);  //不关心客户端的信息
        if(connfd==-1)
        {
            perror("accept");
            exit(-1);
        }
        printf("连接成功 %d 客户端,ip=%s:port=%d\n",connfd-3,inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
        //read/write
        //连接成功一个客户端就开一个线程
        //主线程负责监听和处理客户端连接请求 子线程负责客户端的通信
        *(arr+connfd-4)=1;
        length++;
        pthread_t tid; //保存线程id
        pthread_create(&tid,NULL,do_client,(void *)connfd);
        pthread_detach(tid); //线程资源分离
    }
    //服务器结束，关闭监听套结字
    close(listend);
    return 0;
}

void send_msg(char buf[],int str_len)
{
    int i;
    for(i=0;i<length;i++)
    {
        if(*(arr+i)==1)
        {
            write(i+4,buf,str_len);
        }
    }
}

void *do_client(void *arg)
{
    int connfd = (int) arg;
    int client=0;
    int ret;
    char buf[1024]={0};
    sprintf(buf,"0 %d 号用户",connfd-3);
    write(connfd,buf,sizeof(buf));
    sprintf(buf,"1 %d号用户已加入聊天\n",connfd-3);
    send_msg(buf,sizeof(buf));
    while(1)
    {
        bzero(buf,sizeof(buf)); //清空数组
        ret=read(connfd,buf,sizeof(buf));
        if(0 >= ret)
        {
            printf("client %d  quit\n",connfd-3);
            sprintf(buf,"1 用户 %d 已退出 ",connfd-3);
            close(connfd); //退出一个客户端，就关闭对应的通信套结字
            *(arr+connfd-4)=0;
            send_msg(buf,sizeof(buf));
            pthread_exit(0); //线程退出
        }

        //char *pos=strchr(buf,'\n');
        //char *last;
        //do
        //{
            //last=pos;
          //  pos=strchr(pos+1,'\n');
        //}while(pos!=NULL);
        //*last='\0';

        //读取到数据
        printf("client%d: %s\n",connfd-3,buf);
        if(strcmp(buf,"load")==0)
        {
            loading(connfd);
        }
        else if(strcmp(buf,"break")==0)
        {
            printf("client quit\n");
            close(connfd);
            *(arr+connfd-4)=0;
            pthread_exit(0);
        }
        else
        {
            char out[1024]={0};
            sprintf(out,"1 client%d:%s\n",connfd-3,buf);
            send_msg(out,sizeof(out));
        }
    }

}